import uuid

from django.core.exceptions import ObjectDoesNotExist
from django.db import models
from django.db.models.signals import post_save, post_delete
from django.db.models import Max, When, Value, Case, IntegerField
from django.dispatch import receiver
from django.utils import timezone
from ..CanvasesManagement.models import Canvas
from ..CanvasElementManagement.models import CanvasElement


class LayerGroupManager(models.Manager):
    def create(self, **kwargs):
        """自定义 create 方法，首次保存时不触发父级 z_index 更新"""
        obj = self.model(**kwargs)
        obj._creating = True  # 标记为创建阶段
        obj.save(force_insert=True)
        return obj

    def bulk_update_z_index(self, ids, z_indexes):
        """批量更新 z_index"""
        from django.db.models import Case, When, Value, IntegerField

        if not ids:
            return

        cases = []
        for id_, z_index in zip(ids, z_indexes):
            cases.append(When(id=id_, then=Value(z_index)))

        self.get_queryset().filter(id__in=ids).update(
            z_index=Case(*cases, default='z_index', output_field=IntegerField())
        )


class LayerGroup(models.Model):
    """图层组表"""
    objects = LayerGroupManager()

    id = models.CharField(primary_key=True, default=uuid.uuid4, editable=False,
                          verbose_name="图层组唯一标识", max_length=255)
    canvas = models.ForeignKey(Canvas, on_delete=models.CASCADE,
                               verbose_name="关联画布ID", related_name="layer_groups")
    name = models.CharField("图层组名称", max_length=100)
    visible = models.BooleanField("是否可见", default=True)
    locked = models.BooleanField("是否锁定", default=False)
    z_index = models.IntegerField("组图层", default=0)
    parent = models.ForeignKey('self', on_delete=models.CASCADE,
                               null=True, blank=True, related_name='children', verbose_name="父图层组")
    created_at = models.DateTimeField("创建时间", default=timezone.now)
    updated_at = models.DateTimeField("更新时间", auto_now=True)

    class Meta:
        db_table = 'layer_groups'
        verbose_name = '图层组表'
        verbose_name_plural = '图层组表'
        indexes = [
            models.Index(fields=['z_index'], name='z_index_idx'),
        ]
        ordering = ['z_index']

    def save(self, *args, **kwargs):
        """自定义保存逻辑，拆分为创建和更新阶段"""
        # 判断是否为首次创建（通过 _creating 标记）
        creating = kwargs.pop('force_insert', False) or getattr(self, '_creating', False)

        # 记录旧父级（仅当更新时）
        old_parent = None
        old_z_index = None
        if not creating and self.pk:
            try:
                old_group = LayerGroup.objects.get(pk=self.pk)
                old_parent = old_group.parent
                old_z_index = old_group.z_index
            except ObjectDoesNotExist:
                old_parent = None

        # 调用原生保存逻辑
        super().save(*args, **kwargs)

        # 如果 z_index 变化且非新建，同步到关联元素
        if not creating and old_z_index is not None and self.z_index != old_z_index:
            # 通过映射表找到关联的元素
            try:
                mapping = self.elements_mapping.first()
                if mapping:
                    element = mapping.element
                    if element.z_index != self.z_index:
                        element.z_index = self.z_index
                        element.save(update_fields=['z_index'])
            except ObjectDoesNotExist:
                pass

        # 触发兄弟节点更新（仅在更新且父级变更时）
        if not creating:
            def update_siblings_z_index(parent):
                siblings = LayerGroup.objects.filter(
                    parent=parent,
                    canvas=self.canvas
                ).exclude(id__in=getattr(self, '_exclude_ids', [])).order_by('z_index', 'created_at')

                for index, group in enumerate(siblings):
                    if group.z_index != index:
                        group.z_index = index
                        group.save(update_fields=['z_index'])

            if old_parent != self.parent:
                if old_parent is not None:
                    update_siblings_z_index(old_parent)
                update_siblings_z_index(self.parent)

    def __str__(self):
        return f"{self.name} (画布: {self.canvas.name})"


class LayerGroupMapping(models.Model):
    """图层-组关联表"""
    objects = models.Manager()

    group = models.ForeignKey(LayerGroup, on_delete=models.CASCADE,
                              related_name="elements_mapping", verbose_name="图层组ID")
    element = models.ForeignKey(CanvasElement, on_delete=models.CASCADE,
                                related_name="parent_groups", verbose_name="元素ID")

    class Meta:
        db_table = 'layer_group_mappings'
        verbose_name = '图层-组关联表'
        verbose_name_plural = '图层-组关联表'
        unique_together = ('group', 'element')  # 联合唯一约束
        indexes = [
            models.Index(fields=['group', 'element'], name='group_element_idx')
        ]

    def __str__(self):
        return f"{self.group.name} - {self.element.name}"


@receiver(post_save, sender=CanvasElement)
def handle_element_creation(sender, instance, created, **kwargs):
    """元素创建时自动生成包裹组"""
    if created:
        root_groups = LayerGroup.objects.filter(parent_id=None, canvas=instance.canvas).order_by('z_index')
        max_z = root_groups.aggregate(max_z=Max('z_index'))['max_z']
        group = LayerGroup.objects.create(
            canvas=instance.canvas,
            name=f"{instance.name}{max_z + 1 if max_z is not None else 0}",
            visible=True,
            locked=False,
            z_index=(max_z + 1 if max_z is not None else 0)
        )
        LayerGroupMapping.objects.create(group=group, element=instance)

        # 强制更新元素的 z_index 与组一致
        instance.z_index = group.z_index
        instance.save(update_fields=['z_index'])


@receiver(post_delete, sender=LayerGroup)
def reindex_on_delete(sender, instance, **kwargs):
    """删除时重新索引兄弟节点"""
    siblings = LayerGroup.objects.filter(
        parent=instance.parent,
        canvas=instance.canvas
    ).order_by('z_index')

    for index, group in enumerate(siblings):
        if group.z_index != index:
            group.z_index = index
            group.save()

    # 检查父节点是否为空组
    def delete_empty_parent_group(current_group):
        parent = current_group.parent
        if parent and not parent.children.exists() and not parent.elements_mapping.exists():
            parent.delete()
            delete_empty_parent_group(parent)  # 递归检查上级父节点

    delete_empty_parent_group(instance)


@receiver(post_delete, sender=LayerGroupMapping)
def handle_empty_group(sender, instance, **kwargs):
    """删除最后一个元素时自动删除组"""
    group = instance.group
    if group.elements_mapping.count() == 0:
        # 递归删除空组
        def delete_nested_groups(g):
            for child in g.children.all():
                delete_nested_groups(child)
            g.delete()

        delete_nested_groups(group)
